/**
 * Get the 3D position of the point at the center of the screen.
 */
export function pickCenterPoint(scene) {
  const canvas = scene.canvas;
  const center = new Cesium.Cartesian2(
    canvas.clientWidth / 2,
    canvas.clientHeight / 2);
  return pickOnTerrainOrEllipsoid(scene, center);
}

/**
 * Get the 3D position of the given pixel of the canvas.
 */
export function pickOnTerrainOrEllipsoid(scene, pixel) {
  const ray = scene.camera.getPickRay(pixel);
  const target = scene.globe.pick(ray, scene);
  return target || scene.camera.pickEllipsoid(pixel);
}

/**
 * calculate the resolution based on a distance(camera to position) and latitude value
 */
export function calcResolutionForDistance(distance, latitude, scene) {
  // See the reverse calculation (calcDistanceForResolution) for details
  const canvas = scene.canvas;
  const camera = scene.camera;
  // @ts-ignore TS2341
  const fovy = camera.frustum.fovy; // vertical field of view
  console.assert(!isNaN(fovy));
  const metersPerUnit = 1;

  const visibleMeters = 2 * distance * Math.tan(fovy / 2);
  const relativeCircumference = Math.cos(Math.abs(latitude));
  const visibleMapUnits = visibleMeters / metersPerUnit / relativeCircumference;
  const resolution = visibleMapUnits / canvas.clientHeight;

  return resolution;
}

/**
 * calculate the distance between camera and centerpoint based on the resolution and latitude value
 */
export function calcDistanceForResolution(resolution, latitude, scene) {
  const canvas = scene.canvas;
  const camera = scene.camera;
  // @ts-ignore TS2341
  const fovy = camera.frustum.fovy; // vertical field of view
  const metersPerUnit = 1;

  // number of "map units" visible in 2D (vertically)
  const visibleMapUnits = resolution * canvas.clientHeight;

  // The metersPerUnit does not take latitude into account, but it should
  // be lower with increasing latitude -- we have to compensate.
  // In 3D it is not possible to maintain the resolution at more than one point,
  // so it only makes sense to use the latitude of the "target" point.
  const relativeCircumference = Math.cos(Math.abs(latitude));

  // how many meters should be visible in 3D
  const visibleMeters = visibleMapUnits * metersPerUnit * relativeCircumference;

  // distance required to view the calculated length in meters
  //
  //  fovy/2
  //    |\
  //  x | \
  //    |--\
  // visibleMeters/2
  const requiredDistance = (visibleMeters / 2) / Math.tan(fovy / 2);

  // NOTE: This calculation is not absolutely precise, because metersPerUnit
  // is a great simplification. It does not take ellipsoid/terrain into account.

  return requiredDistance;
}


/**
 * Converts radians to to degrees.
 *
 * @param angleInRadians Angle in radians.
 * @return Angle in degrees.
 */
export function toDegrees(angleInRadians) {
  return angleInRadians * 180 / Math.PI;
}


/**
 * Converts degrees to radians.
 *
 * @param angleInDegrees Angle in degrees.
 * @return Angle in radians.
 */
export function toRadians(angleInDegrees) {
  return angleInDegrees * Math.PI / 180;
}